package turtle.system.util.techindex;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;

import turtle.system.pt.Bar;

import arbor.mining.util.stock.StockEntity;

public class ADXIndex {
	public static final String ADX_STR = "ADX";
	public static final int ADX_PARAMETER = 14;
    public static void attachIndex4StockEntity(ArrayList<StockEntity> db) {
    	double[] TR = new double[db.size()]; Arrays.fill(TR, 0);/*True Range*/
    	double[] plusDM = new double[db.size()]; Arrays.fill(plusDM, 0);/*Directional Movement*/
    	double[] minusDM =new double[db.size()]; Arrays.fill(minusDM, 0);/*Directional Movement*/
    	double[] plusDM14 = new double[db.size()]; Arrays.fill(plusDM14, 0);/*Directional Movement*/
    	double[] minusDM14 =new double[db.size()]; Arrays.fill(minusDM14, 0);/*Directional Movement*/
    	double[] TR14 = new double[db.size()]; Arrays.fill(TR14, 0);/*True Range*/    	
    	
    	double[] plusDI14 = new double[db.size()]; Arrays.fill(plusDI14, 0);/*Directional Index*/
    	double[] minusDI14 = new double[db.size()]; Arrays.fill(minusDI14, 0);/*Directional Index*/
    	double[] DiffDI = new double[db.size()]; Arrays.fill(DiffDI, 0);
    	double[] SumDI =  new double[db.size()]; Arrays.fill(SumDI, 0);
    	double[] DX = new double[db.size()]; Arrays.fill(DX, 0);
    	double[] ADX = new double[db.size()]; Arrays.fill(ADX, 0);
    	
    	/*get TR at first*/
    	/**
    	 * True range. According to the author, the true range is the largest value of 
    	 * the following equations:
    	 * Hight - Lowt
    	 * ABS(Hight - Closet-1)
    	 * ABS(Lowt - Closet-1) 
    	 */
      	for (int i=1;i<db.size();i++)
      	{
          StockEntity today = db.get(i);
          StockEntity yesterday = db.get(i-1);                    
          TR[i] =Math.max(Math.max(today.ohlc.high-today.ohlc.low, Math.abs(today.ohlc.high-yesterday.ohlc.close))
        		  , Math.abs(today.ohlc.low - yesterday.ohlc.close));  
          /*get +DM/-DM at the same time*/
          plusDM[i] = today.ohlc.high - yesterday.ohlc.high > yesterday.ohlc.low - today.ohlc.low ?
        		      Math.max(today.ohlc.high - yesterday.ohlc.high, 0) : 0;

          minusDM[i] = yesterday.ohlc.low - today.ohlc.low > today.ohlc.high - yesterday.ohlc.high ?
        		      Math.max(yesterday.ohlc.low - today.ohlc.low, 0) : 0;
      	}
      	
      	for (int i=0;i<ADX_PARAMETER;i++) {
      		TR14[ADX_PARAMETER] += TR[i];
      		plusDM14[ADX_PARAMETER] += plusDM14[i];
      		minusDM14[ADX_PARAMETER] += minusDM14[i];
      	}
      	double div = (ADX_PARAMETER-1)/(double)ADX_PARAMETER;
      	 		
      	for (int i=ADX_PARAMETER+1;i<db.size();i++) {
      		TR14[i] = TR14[i-1] * div + TR[i];
      		plusDM14[i] = plusDM14[i-1] * div + plusDM[i];
      		minusDM14[i] = minusDM14[i-1] * div + minusDM[i];
      	}
      	for (int i=ADX_PARAMETER+1;i<db.size();i++) {
      		plusDI14[i] =(int)(100*plusDM14[i]/TR14[i]);
      		minusDI14[i] = (int)(100*minusDM14[i]/TR14[i]);
      		DiffDI[i] = Math.abs(plusDI14[i]-minusDI14[i]);
      		SumDI[i] = plusDI14[i]+minusDI14[i];
      		DX[i] = (int)(100*DiffDI[i]/SumDI[i]);
      	}
      	
        for (int i=ADX_PARAMETER;i<=ADX_PARAMETER*2-1;i++) {
      		ADX[ADX_PARAMETER*2-1] += DX[i];
      	}
        ADX[ADX_PARAMETER*2-1] = ADX[ADX_PARAMETER*2-1]/(double)ADX_PARAMETER;
      	for (int i=ADX_PARAMETER*2;i<db.size();i++) {
      		ADX[i] = (ADX[i-1]*(ADX_PARAMETER-1) + DX[i])/(double)ADX_PARAMETER;
      	}
      	
      	for (int i=0;i<db.size();i++) {
      		StockEntity bar = db.get(i);
      		bar.adx = ADX[i];
      	}   	
    }
    /**
     * develop referred from
     * http://technical.traders.com/tradersonline/display.asp?art=278
     * @param db
     */
    public static void attachIndex4Bar(ArrayList<Bar> db) {    	
    	double[] TR = new double[db.size()]; Arrays.fill(TR, 0);/*True Range*/
    	double[] plusDM = new double[db.size()]; Arrays.fill(plusDM, 0);/*Directional Movement*/
    	double[] minusDM =new double[db.size()]; Arrays.fill(minusDM, 0);/*Directional Movement*/
    	double[] plusDM14 = new double[db.size()]; Arrays.fill(plusDM14, 0);/*Directional Movement*/
    	double[] minusDM14 =new double[db.size()]; Arrays.fill(minusDM14, 0);/*Directional Movement*/
    	double[] TR14 = new double[db.size()]; Arrays.fill(TR14, 0);/*True Range*/    	
    	
    	double[] plusDI14 = new double[db.size()]; Arrays.fill(plusDI14, 0);/*Directional Index*/
    	double[] minusDI14 = new double[db.size()]; Arrays.fill(minusDI14, 0);/*Directional Index*/
    	double[] DiffDI = new double[db.size()]; Arrays.fill(DiffDI, 0);
    	double[] SumDI =  new double[db.size()]; Arrays.fill(SumDI, 0);
    	double[] DX = new double[db.size()]; Arrays.fill(DX, 0);
    	double[] ADX = new double[db.size()]; Arrays.fill(ADX, 0);
    	
    	/*get TR at first*/
    	/**
    	 * True range. According to the author, the true range is the largest value of 
    	 * the following equations:
    	 * Hight - Lowt
    	 * ABS(Hight - Closet-1)
    	 * ABS(Lowt - Closet-1) 
    	 */
      	for (int i=1;i<db.size();i++)
      	{
          Bar today = db.get(i);
          Bar yesterday = db.get(i-1);                    
          TR[i] =Math.max(Math.max(today.high-today.low, Math.abs(today.high-yesterday.close))
        		  , Math.abs(today.low - yesterday.close));  
          /*get +DM/-DM at the same time*/
          plusDM[i] = today.high - yesterday.high > yesterday.low - today.low ?
        		      Math.max(today.high - yesterday.high, 0) : 0;

          minusDM[i] = yesterday.low - today.low > today.high - yesterday.high ?
        		      Math.max(yesterday.low - today.low, 0) : 0;
      	}
      	
      	for (int i=0;i<ADX_PARAMETER;i++) {
      		TR14[ADX_PARAMETER] += TR[i];
      		plusDM14[ADX_PARAMETER] += plusDM14[i];
      		minusDM14[ADX_PARAMETER] += minusDM14[i];
      	}
      	double div = (ADX_PARAMETER-1)/(double)ADX_PARAMETER;
      	 		
      	for (int i=ADX_PARAMETER+1;i<db.size();i++) {
      		TR14[i] = TR14[i-1] * div + TR[i];
      		plusDM14[i] = plusDM14[i-1] * div + plusDM[i];
      		minusDM14[i] = minusDM14[i-1] * div + minusDM[i];
      	}
      	for (int i=ADX_PARAMETER+1;i<db.size();i++) {
      		plusDI14[i] =(100*plusDM14[i]/TR14[i]);
      		minusDI14[i] = (100*minusDM14[i]/TR14[i]);
      		DiffDI[i] = Math.abs(plusDI14[i]-minusDI14[i]);
      		SumDI[i] = plusDI14[i]+minusDI14[i];
      		DX[i] = (100*DiffDI[i]/SumDI[i]);
      	}
      	
        for (int i=ADX_PARAMETER;i<=ADX_PARAMETER*2-1;i++) {
      		ADX[ADX_PARAMETER*2-1] += DX[i];
      	}
        ADX[ADX_PARAMETER*2-1] = ADX[ADX_PARAMETER*2-1]/(double)ADX_PARAMETER;
      	for (int i=ADX_PARAMETER*2;i<db.size();i++) {
      		ADX[i] = (ADX[i-1]*(ADX_PARAMETER-1) + DX[i])/(double)ADX_PARAMETER;
      	}
      	
      	for (int i=0;i<db.size();i++) {
      		Bar bar = db.get(i);
      		bar.adx = ADX[i];
      	}
    }
    
    private static void toString(ArrayList<Bar> db) {
    	DateFormat formatterIn = new SimpleDateFormat("yyyy/MM/dd");
    	for (int i=0;i<db.size();i++) {
    		Bar today = db.get(i);
    		System.out.println(today.dateString+","+today.open+","+
    				today.high+","+
    				today.low+","+
    				today.close+","+
    				today.adx);
    	}
    }
}
